https://www.bilibili.com/video/BV1Mb411e7re?p=6
8位单片机:

2.数据类型  所占字节 所占位数      数的表示范围
bit           1bit                 0, 1
char          1Byte   8 位 ???     -128~127                -2^7 ~ 2^7-1
int           2Byte   16位 ???     -32768~32767            -2^15 ~ 2^15-1
short         2Byte   16位 ???     -32768~32767
long          4Byte   32位 ???     -2147483648~2147483647  -2^31 ~ 2^31-1

unsigned char      1Byte   8 位 ???     0~255              0 ~ 2^8-1
unsigned int       2Byte   16位 ???     0~65535            0 ~ 2^16-1
unsigned short int 2Byte   16位 ???     0~65535            0 ~ 2^16-1
unsigned long int  4Byte   32位 ???     0~4294967295       0 ~ 2^32-1

float              4Byte   32位 ???                        3.4e^-38 ~ 3.4e^38
double             8Byte   64位 ???                        1.7e^-308 ~ 1.7e^308

3.没有的数据类型(实测)
unsigned long long


4.其它数据类型
code    : 将数据存储在程序存储区 (ROM 区)(值不可更改), 而不是 RAM 区(data, idata, xdata, 等等)
          //相当于C语言的: malloc(), 例:
          //static code unsigned char Animation_Hello[] = {...}
IROM: 程序存储器
IRAM: 内部RAM
XRAM: 外部RAM

data：RAM低128字节，响应速度最快，采用直接寻址方式

idata：RAM高128字节，采用间接寻址方式，速度相对较慢

bdata：片内RAM，位寻址方式

xdata：外部扩展RAM，采用DPTR访问          char xdata Dest[1];

pdata：外部扩展RAM低256字节，分页寻址（一页256byte）


sfr（special function register）：特殊功能寄存器 声明
sbit（special bit）：特殊位声明

/**
 * TX-1C 的P1口是8个led
 * sfr & sbit: 要在方法外面定义
 * 关于异或^:
 * 0x80^1: 1000 0000 ^ 0000 0001 = 1000 0001
 * 0x90^1: 1001 0000 ^ 0000 0001 = 1001 0001
 */
sfr P1_test = 0x90;      //直接取地址, 声明P1口寄存器，物理地址为0x90

sbit P1_1_test = 0x91;       //直接取地址, 声明P1寄存器的第1位
sbit P1_1_test = 0x90^1;        //寄存器地址取位地址
sbit P1_1_test = P1_test^1;  //寄存器名取位地址

void main() {
    //间隔点亮
    P1_test = 0xaa;
    //点了1个灯
    P1_1_test = 0;
    while (1);
}


5.输出类型(UART_Utils.h 示例)
/**
 * https://blog.csdn.net/qq_37429313/article/details/114537072
 * % <[>flags<]> <[>width<]> <[>.precision<]> <[>{b|B|l|L}<]> type
 * flags: 标志字段，打印+/-符号和空白，小数点以及八进制和十六进制前缀
 *       -          左对齐指定字段宽度的输出。
 *       +           如果输出是带符号类型，则在输出值前加上+或-前缀
 *       blank(空白) 如果输出值是有符号正值，则将其前缀为"空格"。 否则，不带空格前缀
 *       #	        当分别与0，0x和0X字段类型一起使用时，将非零输出值前缀为0、0x或0X。
 *                  与e，E，f，g和G字段类型一起使用时，＃标志强制输出值包含小数点。
                    在所有其他情况下，＃标志将被忽略。
 *
 * width: 宽度字段, 指定最少要打印的字符数。
 *        如果输出值中的字符数小于宽度，则在左侧（默认情况下）或右侧（指定-标志时）添加"空格"以填充到最小宽度。
 *        如果width前缀为’0’，则填充零而不是空格。 width字段不会截断输出。
 *        如果输出值的长度超过指定的宽度，则输出所有字符
 *
 * .precision: 精度, 精度字段是一个非负数，它指定要打印的字符数，有效数字数或小数位数。
 *             下表中指定了浮点数时，精度字段可能会导致输出值的截断或舍入。
 *      d,u,o,x,X "precision" 指定输出值中包含的最小位数。 如果参数中的位数超过精度字段中定义的位数，则位数不会被截断。 如果参数中的位数小于precision字段，则在输出值的左侧填充零。
 *      f         "precision" 指定小数点右边的位数。最后一位四舍五入。
 *      e.E       "precision" 指定小数点右边的位数。最后一位四舍五入。
 *      g,G       "precision" 指定输出值中的最大有效位数。
 *      s         "precision" 指定输出值中的最大字符数。不输出多余的字符。
 *      c,p       "precision" 对这些字段类型没有影响.
 *
 * {b|B|l|L}:
 *      b  紧接在类型字符之前，以分别为d，i，u，o，x和X指定 char 类型。
 *      B
 *      l 紧接在类型字符之前，以分别为d，i，u，o，x和X指定 long 类型。
 *      L
 *
 * type: 类型字段, 指定将参数解释为字符，字符串，数字还是指针
 *      d	int	            "有符号"十进制
 *      u	unsigned int	无符号十进制
 *      o	unsigned int	无符号八进制
 *      x	unsigned int	无符号十六进制(小写)
 *      X	unsigned int	无符号十六进制(大写)
 *      f	float           浮点数
 *      e	float           科学计数法(e)
 *      E	float           科学计数法(E)
 *      g	float           灵活选择e或者f的格式，让数据的输出更加好看有效
 *      G	float           灵活选择E或者f的格式，让数据的输出更加好看有效
 *      c	char            一个字符
 *      s	*               一串以空字符（’\ 0’）结尾的字符。
 *      p	*               十六进制地址。
 *
 *
 * 示例: （KEIL里扩展出了b,h,l来对输入字节宽的设置：b八位(256)；h十六位(65535)；l三十二位)???
 *      %bu 8 位无符号整数；默认 unsigned char, 例: UART_sendStringFormat(1, "%bu", 123); //123
 *      %u                       unsigned int
 *      %lu                      unsigned long
 *      %bd 8 位有符号整数; 默认 char
 *      %d    有符号 int
 *      %ld    有符号 long
 *      %bx 表示 8 位十六进制整数；
 *      %x
 *      %lx
 *      printf ("%*f != %*g\n", (int)8, f, (int)8, g);   //float f = 10.0, g = 22.95;
 */
void printf_test() {
    
    float floatF2 = -5.23456789F;
    float floatF3 = 0.23456789F;
    float floatF4 = 5.23456789F;
    float floatF5 = 5.2340000F;
    float f1 = -3.2435718765676567F;
    double lf2 = 0.2435718765676567F;
    double lf3 = 3.2435718765676567F;
    UART_sendStringFormat(1, "a=%bu, b=%c", 123, 'A');  //(a=123, b=A) 整数默认是unsigned char
    UART_sendStringFormat(1, "%d", Int);                //(-123)
    UART_sendStringFormat(1, "%u", UInt);               //(123)
    /**
     * %g: f和e类型中较短的, 后面"连续0"会被舍弃
     * if(整数部分=0) 小数点后默认6位 (第7位会被 四舍五入)
     * if(整数部分≠0) 小数点后默认5位 (第6位会被 四舍五入)
     * %.7g:
     *      7不能更大(更大无效), 如果整数部分=0, 小数点后最多7位(否则最多6位)
     */
    UART_sendStringFormat(1, "%g", floatF2);    //%g  : (-5.23457)
    UART_sendStringFormat(1, "%g", floatF3);    //%g  : (0.234568)
    UART_sendStringFormat(1, "%g", floatF4);    //%g  : (5.23457)
    UART_sendStringFormat(1, "%g", floatF5);    //%g  : (5.234) 后面"连续0"会被舍弃
    UART_sendStringFormat(1, "%.7g", f1);       //%.7g: (-3.243572)
    UART_sendStringFormat(1, "%.7g", lf2);      //%.7g: (0.2435719)
    UART_sendStringFormat(1, "%.7g", lf3);      //%.7g: (3.243572)
    UART_sendStringFormat(1, "%bX", 0xA8);      //%bX : (A8)
    UART_sendStringFormat(1, "%bX", 168);       //%bX : (A8)
    UART_sendStringFormat(1, "%lX", Number);    //%bX : (A8)        unsigned long int Number = 168;
}


/**
 * 可位寻址/不可位寻址：在单片机系统中，操作任意寄存器或者某一位的数据时，必须给出其物理地址，
 * 又因为一个寄存器里有8位，所以位的数量是寄存器数量的8倍，
 * 单片机无法对所有位进行编码，故每8个寄存器中，只有一个是可以位寻址的。
 * 对不可位寻址的寄存器，若要只操作其中一位而不影响其它位时，可用“&=”、“|=”、“^=”的方法进行位操作
 */








